package edu.imac.angryfood.component;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Timer;

import org.jbox2d.common.Vec2;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;

import edu.imac.angryfood.shapes.Circle;
import edu.imac.angryfood.shapes.Rectangle;
import edu.imac.angryfood.world.Body;
import edu.imac.angryfood.world.World;


/** The abstract class for the projectiles */

public abstract class AbstractProjectile extends Body {
	
	/** if the projectile is being draged */
	private Boolean draged;
	/** if the projectile has been droped */
	private Boolean droped;
	protected Image img;
	protected String imgName;
	/** if the projectiles has been clicked (the action associated to the projectile has been done */
	protected Boolean clicked;
	/** type of the shape (Rectangle or Circle) */
	protected String shapeType;
	protected int width;
	protected int height;
	protected float radius;
	/** the number of the current projectile */
	public static int current=0;
	/** the number of projectiles in the level */
	public static int nbProj=0;
	/** the x value of the launching area */
	public static int xInitXML;
	/** the y value of the launching area */
	public static int yInitXML;
	/** the number of the projectile (order in which it will be launched) */
	protected int num;
	/** timer for the move of the projectile to the launching area */
	protected Timer tNext;
	/** if the projectile can currently be draged (in position in the launching area)*/
	protected boolean dragable;
	/** timer to pass to the next projectile if the current hasn't touched anything */
	protected Timer tLaunched;
	/** if the projectile has touched something */
	protected boolean collided;

	
	/** constructor for circle projectiles
	 * 
	 * @param x x position of the projectile
	 * @param y y position of the projectile
	 * @param radius radius of the projectile
	 * @param droped if the projectile has already been droped
	 * @param num the order in which the projectile will be launched
	 * @param image the name of the image's file
	 */
	
	public AbstractProjectile (int x, int y, float radius, boolean droped, int num, String image) throws SlickException{
		
		super(new Circle(radius),  x, y, !droped);
		imgName = image;
		setImg(new Image("res/img/game/"+image).getFlippedCopy(false, true));
		this.draged=false;
		this.droped=droped;
		clicked=false;
		this.radius=radius;
		this.setShapeType("Circle");
		this.num=num;
		if (num==0)
			dragable=true;
		else
			dragable=false;
		super.setType("PROJECTILE");
	}
	
	/** constructor for rectangle projectiles
	 * 
	 * @param x x position of the projectile
	 * @param y y position of the projectile
	 * @param width width of the projectile
	 * @param height height of the projectile
	 * @param droped if the projectile has already been droped
	 * @param num the order in which the projectile will be launched
	 * @param image the name of the image's file
	 */
	
	public AbstractProjectile (int x, int y, int width, int height, boolean droped, int num, String image) throws SlickException{
		
		super(new Rectangle(width, height),  x, y, !droped);
		imgName = image;
		setImg(new Image("res/img/game/"+image).getFlippedCopy(false, true));
		this.draged=false;
		this.droped=droped;
		clicked=false;
		this.width = width;
		this.height = height;
		this.setShapeType("Rectangle");
		this.num=num;
		if (num==0)
			dragable=true;
		else
			dragable=false;
		super.setType("PROJECTILE");
	}
	

	public boolean isCollided() {
		return collided;
	}

	public boolean isDropped() {
		return droped;
	}
	
	public boolean isDragable() {
		return dragable;
	}

	public Boolean getClicked() {
		return clicked;
	}

	public int getNum() {
		return num;
	}

	public float getRadius() {
		return radius;
	}

	public Boolean getDraged() {
		return draged;
	}

	public void setDraged(Boolean draged) {
		this.draged = draged;
	}

	public Boolean getDroped() {
		return droped;
	}

	public void setDroped(Boolean droped) {
		this.droped = droped;
	}
	
	public void setClicked(Boolean clicked) {
		this.clicked = clicked;
	}

	public void setImg(Image img) {
		this.img = img;
	}
	public Image getImg() {
		return img;
	}
	
	public String getImgName() {
		return imgName;
	}
	
	public String getShapeType() {
		return shapeType;
	}

	public static void setCurrent(int current) {
		AbstractProjectile.current = current;
	}

	public void setShapeType(String shapeType) {
		this.shapeType = shapeType;
	}

	public int getWidth() {
		return width;
	}

	public int getHeight() {
		return height;
	}

	/** to launch the projectiles
	 * @param impX the impulsion given on the x axis
	 * @param impY the impulsion given on the y axis
	 * @param world the world that contains the game
	 */
	public void launch (float impX, float impY, final World world){
		dragable=false;
		Vec2 imp = new Vec2();
		imp.x = impX;
		imp.y = impY;
		getJboxBody().applyImpulse(imp, getJboxBody().getWorldCenter());
		tLaunched = new Timer (3000, new ActionListener(){
			public void actionPerformed(ActionEvent e){
				inactivity(world);
				tLaunched.stop();
			}

		});
		tLaunched.start();	
	}	
	
	/** the action that happens when the user clicks and the projectile is in the air
	 * 
	 * @param world the world that contains the game
	 * @throws SlickException
	 */
	abstract public void click(World world) throws SlickException;

	/** to set the next projectile as the current, and making it move to the launching area
	 * 
	 * @param world the world that contains the game
	 */
	public void next(final World world){
		AbstractProjectile.current++;
		tNext = new Timer (40, new ActionListener(){
			public void actionPerformed(ActionEvent e){
				int cpt=0;
				for (AbstractProjectile proj : world.getProjectiles()){
					Vec2 direction;
					//if it's the current projectile, it moves to the launching area
					if (proj.getNum()==current){
						if (proj.getJboxBody().getWorldCenter().x < xInitXML && proj.getJboxBody().getWorldCenter().y < yInitXML){
							direction = new Vec2 (xInitXML-proj.getJBoxBody().getWorldCenter().x, yInitXML-proj.getJBoxBody().getWorldCenter().y);
							double norm=Math.sqrt(Math.pow(direction.x, 2)+Math.pow(direction.y, 2));
							proj.translate((int) (direction.x*10/norm), (int) (direction.y*10/norm));
							cpt++;
						}
					}
					//else, it approaches just the launching area 
					else if (proj.getNum()>current){
						if (proj.getJboxBody().getWorldCenter().x < xInitXML-100-(proj.getNum()-current-1)*50){
							direction = new Vec2 (1,0);
							double norm=Math.sqrt(Math.pow(direction.x, 2)+Math.pow(direction.y, 2));
							proj.translate((int) (direction.x*10/norm), (int) (direction.y*10/norm));
							cpt++;
						}
					}

					
				}
				//when all the projectiles are set in place, the current is dragable
				if (cpt==0){
					tNext.stop();
					for (AbstractProjectile proj : world.getProjectiles()){
						if (proj.getNum()==current){
							proj.dragable=true;
						}
					}
				}
				
			}
		});
		tNext.start();
		
	}

	/** the action that happens when the projectile collides something
	 * 
	 * @param world the world that contains the game
	 */
	public abstract void collision(World world);
	
	/** the action that happens when the projectile collides nothing after 3 seconds
	 * 
	 * @param world the world that contains the game
	 */
	public void inactivity (World world){
		if (!collided){
			collided=true;
			next(world);
			if (tLaunched instanceof Timer){
				tLaunched.stop();
			}
			clicked=true;	
		}
	}
	
}
